
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.hlkj.pay.app.merchant.IMerchantConfigAppService;
import com.hlkj.pay.common.constants.MqConstant;
import com.hlkj.pay.config.ExtRocketMQTemplate;
import com.hlkj.pay.dto.common.DefaultConfig;
import com.hlkj.pay.dto.common.OrderStatusDto;
import com.hlkj.pay.dto.merchant.config.MerchantPaymentConfigDto;
import com.hlkj.pay.dto.order.RouterOrderMessageDto;
import com.hlkj.pay.dto.order.StatisticsDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDetailDO;
import com.hlkj.pay.service.common.IPlatFormConfigService;
import com.hlkj.pay.service.merchant.IMerchantService;
import com.hlkj.pay.util.MerchantUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;

/**
 * @author HlpayTeam
 * @date 2024/10/10 15:30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderHandler {

    private final IMerchantService merchantService;

    private final ExtRocketMQTemplate extRocketMQTemplate;

    @Value("${rocketmq.producer.order_delay_level:2}")
    private Integer orderDelayLevel;

    @Value("${rocketmq.consumer.order_delay_consumer_max_count:15}")
    private Integer orderDelayConsumerMaxCount;

    private final OrderNotifyHandler orderNotifyHandler;

    private final IPlatFormConfigService platFormConfigService;

    private final IMerchantConfigAppService merchantConfigAppService;

    /**
     * 提交订单
     *
     * @param payOrderDO
     */
    void submitPayOrder(PayOrderDO payOrderDO) {
        // 统计消息
        sendStatistics(payOrderDO, PayOrderEnums.STATISTICS_TYPE.SUBMIT_ORDER);
        // 订单主动查询消息 10s 查询一次
        // 延迟消息支持的时间 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
        sendOrderStatus(orderDelayLevel, payOrderDO.getPayOrderNo(), PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS);
        if(!PayOrderEnums.PAY_ORDER_STATUS.INIT.getCode().equals(payOrderDO.getState())){
            sendRouterMessage(payOrderDO);
        }
    }

    void sendRouterMessage(PayOrderDO payOrderDO) {
        RouterOrderMessageDto orderStatusDto = new RouterOrderMessageDto();
        orderStatusDto.setAppId(payOrderDO.getAppId());
        orderStatusDto.setMchChannelCode(payOrderDO.getMchChannelCode());
        orderStatusDto.setAutCode(payOrderDO.getAutCode());
        orderStatusDto.setPayOrderNo(payOrderDO.getPayOrderNo());
        orderStatusDto.setState(payOrderDO.getState());
        try {
            extRocketMQTemplate.send(MqConstant.ORDER_ROUTER_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    /**
     * 提交订单
     *
     * @param refundOrderDO
     */
    void refundOrder(RefundOrderDO refundOrderDO) {
        orderNotifyHandler.orderNotify(refundOrderDO.getRefundOrderNo(), 1,PayOrderEnums.ORDER_STATUS_TYPE.REFUND_STATUS);
        // 只有退款成功才算
        if (PayOrderEnums.REFUND_STATUS.REFUND.getCode().equals(refundOrderDO.getRefundStatus())) {
            // 统计消息
            sendStatistics(refundOrderDO);
            // 内扣手续费计算topic
            DefaultConfig defaultConfig = platFormConfigService.getDefaultConfig();
            DefaultConfig.OtherConfig otherConfig = defaultConfig.getOtherConfig();
            if (otherConfig != null && CommonEnum.YES_NO_TYPE.YES.getCode().equals(otherConfig.getRefundFlag())) {
                sendRefundFeeCalculate(refundOrderDO);
            }
            else {
                log.info("不退手续费不发送 扣分计算 topic:{}", refundOrderDO.getRefundOrderNo());
            }
        }
    }

    /**
     * 提交订单
     *
     * @param payOrderDO
     */
    void payOrder(PayOrderDO payOrderDO) {
        // 支付成功通知
        orderNotifyHandler.orderNotify(payOrderDO.getPayOrderNo(), null,PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS);
        if (payOrderDO.getFeeAmount() != null && payOrderDO.getFeeAmount().compareTo(new BigDecimal(0)) != 0) {
            // 商户手续费率扣减
            merchantService.updateMerchantFeeAmount(payOrderDO.getOrderSn(), payOrderDO.getFeeAmount(), CommonEnum.YES_NO_TYPE.NO);
        }
        // 内扣手续费计算
        sendPayFeeCalculate(payOrderDO);
    }

    /**
     * 代理订单
     * 
     * @param merchantPaymentDetailDO
     */
    public void paymentOrder(MerchantPaymentDetailDO merchantPaymentDetailDO) {
        orderNotifyHandler.orderNotify(merchantPaymentDetailDO.getDetailPaymentId(), 1,PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS);
        MerchantPaymentConfigDto merchantPaymentConfigDto = merchantConfigAppService.queryPaymentConfig(merchantPaymentDetailDO.getSn());
        if (merchantPaymentConfigDto != null && CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantPaymentConfigDto.getStatus())) {
            // 内扣手续费计算
            sendPaymentFeeCalculate(merchantPaymentDetailDO);
        }
    }

    /**
     * 费率计算message
     * 
     * @param merchantPaymentDetailDO
     */
    private void sendPaymentFeeCalculate(MerchantPaymentDetailDO merchantPaymentDetailDO) {
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(merchantPaymentDetailDO.getDetailPaymentId());
        orderStatusDto.setOrderStatusType(PayOrderEnums.ORDER_STATUS_TYPE.PAYMENT_ORDER_STATUS.getCode());
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.FEE_CALCULATE_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    public static String sn(String sn, String subSn) {
        if (StringUtils.hasText(subSn)) {
            return subSn;
        }
        return sn;
    }

    void sendOrderStatus(Integer delay, String orderNo, PayOrderEnums.ORDER_STATUS_TYPE orderStatusType) {
        if (delay > orderDelayConsumerMaxCount) {
            log.info("订单状态查询已超过30m等级,结束查询 order:{}", orderNo);
            return;
        }
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(orderNo);
        orderStatusDto.setOrderStatusType(orderStatusType.getCode());
        orderStatusDto.setDelayLevel(delay);
        if (orderStatusDto.getTotalConsumerCount() == null) {
            orderStatusDto.setTotalConsumerCount(1);
        }
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        orderStatusDto.setTotalConsumerCount(orderStatusDto.getTotalConsumerCount() + 1);
        try {
            // 延迟消息支持的时间 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
            extRocketMQTemplate.sendDelay(delay, MqConstant.ORDER_STATUS_RECORD_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    void sendOrderStatus(OrderStatusDto orderStatusDto) {
        if (orderStatusDto.getDelayLevel() == null) {
            orderStatusDto.setDelayLevel(orderDelayLevel);
        }
        if (orderStatusDto.getDelayLevel() > orderDelayConsumerMaxCount) {
            log.info("订单状态查询已超过30m等级,结束查询 order:{}", orderStatusDto.getOrderNo());
            return;
        }
        orderStatusDto.setDelayLevel(orderStatusDto.getDelayLevel() + 1);
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        if (orderStatusDto.getTotalConsumerCount() == null) {
            orderStatusDto.setTotalConsumerCount(1);
        }
        orderStatusDto.setTotalConsumerCount(orderStatusDto.getTotalConsumerCount() + 1);
        try {
            // 延迟消息支持的时间 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
            extRocketMQTemplate.sendDelay(orderStatusDto.getDelayLevel(), MqConstant.ORDER_STATUS_RECORD_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    public void sendStatistics(PayOrderDO payOrderDO, PayOrderEnums.STATISTICS_TYPE statisticsType) {
        StatisticsDto statisticsDto = new StatisticsDto();
        switch (statisticsType) {
            case PAY_ORDER:
                if (payOrderDO.getPayAmount() != null) {
                    statisticsDto.setPayOrderAmount(MerchantUtils.bigDecimalToString(payOrderDO.getPayAmount()));
                }
                else {
                    statisticsDto.setPayOrderAmount(MerchantUtils.bigDecimalToString(payOrderDO.getAmount()));
                }
                statisticsDto.setFeeAmount(MerchantUtils.bigDecimalToString(payOrderDO.getFeeAmount()));
                if (payOrderDO.getChannelFeeAmount() != null) {
                    statisticsDto.setChannelFeeAmount(MerchantUtils.bigDecimalToString(payOrderDO.getChannelFeeAmount()));
                }
                else {
                    statisticsDto.setChannelFeeAmount("0");
                }
                break;
            case SUBMIT_ORDER:
                statisticsDto.setSubmitOrderAmount(MerchantUtils.bigDecimalToString(payOrderDO.getAmount()));
                break;
            default:
                return;
        }
        statisticsDto.setCreateTime(payOrderDO.getCreateTime());
        statisticsDto.setStatisticsType(statisticsType.getCode());
        statisticsDto.setSn(payOrderDO.getOrderSn());
        statisticsDto.setPayWayCode(payOrderDO.getPayWayCode());
        statisticsDto.setAppId(payOrderDO.getAppId());
        statisticsDto.setMchChannelCode(payOrderDO.getMchChannelCode());
        statisticsDto.setOrderNo(payOrderDO.getPayOrderNo());
        statisticsDto.setChannelCode(payOrderDO.getChannelCode());
        statisticsDto.setAutCode(payOrderDO.getAutCode());
        statisticsDto.setSendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.ORDER_STATISTICS_TOPIC, statisticsDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    protected void sendStatistics(RefundOrderDO refundOrderDO) {
        StatisticsDto statisticsDto = new StatisticsDto();
        statisticsDto.setRefundAmount(MerchantUtils.bigDecimalToString(refundOrderDO.getRefundAmount()));
        statisticsDto.setCreateTime(refundOrderDO.getCreateTime());
        statisticsDto.setStatisticsType(PayOrderEnums.STATISTICS_TYPE.REFUND_ORDER.getCode());
        statisticsDto.setSn(refundOrderDO.getSn());
        statisticsDto.setPayWayCode(refundOrderDO.getPayWayCode());
        statisticsDto.setAppId(refundOrderDO.getAppId());
        statisticsDto.setMchChannelCode(refundOrderDO.getMchChannelCode());
        statisticsDto.setChannelCode(refundOrderDO.getChannelCode());
        statisticsDto.setOrderNo(refundOrderDO.getRefundOrderNo());
        statisticsDto.setSendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.ORDER_STATISTICS_TOPIC, statisticsDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    protected void sendPayFeeCalculate(PayOrderDO payOrderDO) {
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(payOrderDO.getPayOrderNo());
        orderStatusDto.setOrderStatusType(PayOrderEnums.ORDER_STATUS_TYPE.PAY_ORDER_STATUS.getCode());
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.FEE_CALCULATE_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }
    public void sendWithdrawFeeCalculate(String payOrderNo) {
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(payOrderNo);
        orderStatusDto.setOrderStatusType(PayOrderEnums.ORDER_STATUS_TYPE.WITHDRAW_ORDER_STATUS.getCode());
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.FEE_CALCULATE_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

    protected void sendRefundFeeCalculate(RefundOrderDO refundOrderDO) {
        OrderStatusDto orderStatusDto = new OrderStatusDto();
        orderStatusDto.setOrderNo(refundOrderDO.getRefundOrderNo());
        orderStatusDto.setOrderStatusType(PayOrderEnums.ORDER_STATUS_TYPE.REFUND_STATUS.getCode());
        orderStatusDto.setDelaySendTime(System.currentTimeMillis());
        try {
            extRocketMQTemplate.send(MqConstant.FEE_CALCULATE_TOPIC, orderStatusDto);
        }
        catch (Exception e) {
            log.error("mq 发送异常:{}", e.getMessage(), e);
        }
    }

}
